#pragma once

#include "JsonUtil.h"
#include <iostream>
#include <iomanip>
#include <sstream>
#include <random>
#include <chrono>
#include <string>
#include <atomic>
#include <unordered_map>
#include <memory>
#include <functional>
#include <vector>
#include <stdio.h>
#include <time.h>
#include <string_view>
#include <mutex>
#include <unordered_set>
#include <set>
#include <future>
#include "muduo/net/TcpConnection.h"
#include "muduo/net/TcpClient.h"
#include "muduo/net/TcpServer.h"
#include "muduo/net/EventLoop.h"
#include "muduo/net/EventLoopThread.h"
#include "muduo/base/CountDownLatch.h"

using std::cout;
using std::endl;
using std::future;
using std::mutex;
using std::promise;
using std::set;
using std::string;
using std::stringstream;
using std::unique_lock;
using std::unordered_map;
using std::unordered_set;
using std::vector;

namespace rpc
{
// 请求字段的宏
#define KEY_METHOD "method"       // 方法名称
#define KEY_PARAMS "params"       // 方法参数
#define KEY_TOPIC_KEY "topic_key" // 主题名
#define KEY_TOPIC_MSG "topic_msg" // 主题消息
#define KEY_OPTYPE "optype"       // 操作类型
#define KEY_HOST "host"           // 主机信息
#define KEY_HOST_IP "ip"          // 主机ip
#define KEY_HOST_PORT "port"      // 主机port
#define KEY_RCODE "rcode"         // 响应码
#define KEY_RESULT "result"       // 响应结果

    // 消息类型定义
    enum class MType
    {
        REQ_RPC = 0, // RPC 请求和响应
        RSP_RPC,
        REQ_TOPIC, // topic 请求和响应
        RSP_TOPIC,
        REQ_SERVICE, // service 请求和响应
        RSP_SERVICE,
    };

    // 响应码类型
    enum class RCode
    {
        RCODE_OK = 0,
        RCODE_PARSE_FAILED,
        RCODE_ERROR_MSGTYPE,
        RCODE_INVALID_MSG,
        RCODE_DISCONNECTED,
        RCODE_INVALID_PARAMS,
        RCODE_NOT_FOUND_SERVICE,
        RCODE_INVALID_OPTYPE,
        RCODE_NOT_FOUND_TOPIC,
        RCODE_INTERNAL_ERROR
    };

    // rpc 请求类型
    enum class RType
    {
        REQ_ASYNC = 0, // 异步: 返回异步对象，在需要的时候通过异步对象获取响应结果（还未收到结果会阻塞）
        REQ_CALLBACK,  // 回调函数: 设置回调函数，通过回调函数对响应进⾏处理
    };

    // 主题操作类型
    enum class TopicOpType
    {
        TOPIC_CREATE = 0, // 创建
        TOPIC_DELETE,     // 删除
        TOPIC_SUBCRIBE,   // 订阅
        TOPIC_CANCEL,     // 取消订阅
        TOPIC_PUBLISH,    // 发布消息
    };

    // 服务操作类型定义
    enum class ServiceOpType
    {
        SERVICE_REGISTRY = 0, // 创建
        SERVICE_DISCOVER,     // 发现
        SERVICE_ONLINE,       // 上线
        SERVICE_OFFLINE,      // 下线
        SERVICE_UNKONW,
    };

    static string errReason(RCode code)
    {
        static unordered_map<RCode, string> errMap = {
            {RCode::RCODE_OK, "成功处理!"},
            {RCode::RCODE_PARSE_FAILED, "消息解析失败!"},
            {RCode::RCODE_ERROR_MSGTYPE, "消息类型错误!"},
            {RCode::RCODE_INVALID_MSG, "无效消息!"},
            {RCode::RCODE_DISCONNECTED, "连接已断开!"},
            {RCode::RCODE_INVALID_PARAMS, "无效的Rpc参数!"},
            {RCode::RCODE_NOT_FOUND_SERVICE, "没有找到对应的服务!"},
            {RCode::RCODE_INVALID_OPTYPE, "无效的操作类型!"},
            {RCode::RCODE_NOT_FOUND_TOPIC, "没有找到对应的Topic!"},
            {RCode::RCODE_INTERNAL_ERROR, "内部错误!"}};

        unordered_map<RCode, string>::iterator iter = errMap.find(code);
        if (iter == errMap.end())
        {
            return "未知错误!";
        }

        return iter->second;
    }

    /*
    UUID(Universally Unique Identifier), 也叫通⽤唯⼀识别码，通常由32位16进制数字字符组成。
    UUID的标准型式包含32个16进制数字字符，以连字号分为五段，形式为8-4-4-4-12的32个字符，
    如：550e8400-e29b-41d4-a716-446655440000。
    */
    string uuid()
    {
        stringstream ss;
        // 构造一个机器随机数对象
        std::random_device rd;

        // 以机器随机数为种⼦构造伪随机数对象
        std::mt19937 generator(rd());
        // 构造限定数据范围的对象
        std::uniform_int_distribution<int> distribution(0, 255);
        // ⽣成个随机数，按照特定格式组织成为进制数字字符的字符串
        for (int i{}; i < 8; i++)
        {
            if (i == 4 || i == 6)
                ss << "-";

            ss << std::setw(2) << std::setfill('0') << std::hex << distribution(generator);
        }
        ss << "-";

        // 定义⼀个字节序号，逐字节组织成为进制数字字符的字符串
        static std::atomic<size_t> seq(1);
        size_t cur = seq.fetch_add(1);

        for (int i{7}; i >= 0; i--)
        {
            if (i == 5)
                ss << "-";

            ss << std::setw(2) << std::setfill('0') << std::hex << ((cur >> (i * 8)) & 0xFF);
        }
        return ss.str();
    }

} // rpc